#!/usr/bin/env python                                                           
""" Test the netio.py - server """                                              

from netio import *                                                             

import socket                                                                   
import time                                                                     
import logging                                                                  
import functools

# config test                                                                   
logging.basicConfig(format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", 
        level=logging.DEBUG)                  

cursor = 0
last_sended = 0
fd_sock = {}                                                                
requests = []
nio = NetEventLoop.Instance()

def ReadWriteCallback(fd, events):

    global cursor 
    global last_sended
    try:                                                                        
        sock = fd_sock[fd]                                                  
    except KeyError,e:
        logging.error("nonexist fd %d", fd, exc_info=True)                      
        raise

    if events & select.EPOLLERR:                                                
        logging.warning("fd %d has something error", fd)                        
        sock.close()
        nio.CancelEvents(fd)
        return
    elif events & select.EPOLLIN:
        logging.debug("fd %d has read event", fd)
        try:
            while True:
                data = sock.recv(1024)
                if not data:
                    logging.debug("Client close the connection")
                    nio.CancelEvents(fd)
                    break
                requests.append(data)
        except Exception, e:
            if (getattr(e, 'errno', None) == errno.EWOULDBLOCK or     
                   (isinstance(getattr(e, 'args', None), tuple) and
                       len(e.args)==2 and e.args[0] == errno.EWOULDBLOCK)):
                logging.debug("Read until EWOULDBLOCK")
                pass
            else:
                logging.error("Exception in recv()")

    elif events & select.EPOLLOUT:
        #logging.debug("fd %d has write event", fd)

        if not requests:
            #logging.debug("requests not ready yet")
            pass
        elif cursor >= len(requests):
            #logging.debug("All have been sended")
            pass
        else:
            try:                                                                        
                sock = fd_sock[fd]                                                  
            except KeyError,e:
                logging.error("nonexist fd %d", fd, exc_info=True)                      
                raise

            try:
                data = ''
                for i in range(0,1000):
                    data += requests[cursor][0:-1]
                    data += " "
                tosend = len(data) - last_sended
                sended = 0
                while sended < tosend:
                    sended += sock.send(data[(last_sended+sended):])
            except Exception, e:
                logging.error("fd %d send() not available yet", fd)   
            
            logging.debug("sended: %d", sended)

            if sended >= tosend:
                cursor += 1
                last_sended = 0
            else:
                last_sended += sended 
    else:
        logging.error("Unknown events", exc_info=True)

 
def ListenSocketCallback(fd, events):
    logging.debug("listening fd %d events, event:%d", fd, events)
    sock = fd_sock[fd]

    if events & select.EPOLLERR:
        logging.warning("fd %d has something error", fd)
    elif events & select.EPOLLIN:
        logging.debug("is EPOLLIN, accept")
        io_sock, client_addr = sock.accept()
        io_sock.setblocking(0)
        io_sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)

        io_sock_fd = io_sock.fileno()

        fd_sock[io_sock_fd] = io_sock

        logging.debug("Client comming, new socket:%d", io_sock_fd)

        SetNonBlock(io_sock_fd)

        nio.AddEvents(io_sock_fd, ReadWriteCallback, 
                select.EPOLLIN | select.EPOLLOUT)
    else:
        logging.error("Unknown events in fd %d, events %d", fd, events)


def OneFDReadAndWrite():
    listen_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    listen_sock_fd = listen_sock.fileno()
    SetNonBlock(listen_sock_fd)

    fd_sock[listen_sock_fd] = listen_sock 

    port = 15000
    listen_sock.bind(('127.0.0.1', port))
    logging.debug("Bind to port %d succeed", port)

    listen_sock.listen(5)
    
    nio.AddEvents(listen_sock_fd, ListenSocketCallback, 
            select.EPOLLIN)
    
    nio.StartLoop()

if __name__ == '__main__':
    OneFDReadAndWrite()
